package com.hyrluntan.forum.controller;

import com.google.code.kaptcha.Constants;
import com.hyrluntan.forum.common.AppResult;
import com.hyrluntan.forum.common.LogAnnotation;
import com.hyrluntan.forum.common.ResultCode;
import com.hyrluntan.forum.config.AppConfig;
import com.hyrluntan.forum.model.User;
import com.hyrluntan.forum.services.IUserService;
import com.hyrluntan.forum.utils.*;
import io.micrometer.core.instrument.util.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

@SuppressWarnings("ALL")
@Slf4j
// 对Controller进行API接口的描述
@Api(tags = "用户接口")
// 标识了个Controller并且响应时返回Body中的数据
@RestController
// 指定路径映射 - 路由映射，一级路径
@RequestMapping("/user")
// 解决跨域
@CrossOrigin

public class UserController {
    // 注⼊业务层
    @Resource
    private IUserService userService;

    /**
     * 用户注册
     *
     * @param username       用户名
     * @param nickname       昵称
     * @param password       密码
     * @param passwordRepeat 确认密码
     * @return
     */
    @ApiOperation("用户注册")
    // 指定接⼝URL映射
    @PostMapping("/register")
    // 加上此接口，表示要对此接口记录日志
    @LogAnnotation(module="登录",operator="登录操作")
    public AppResult register(@ApiParam("用户名") @RequestParam("username") @NonNull String username,
                              @ApiParam("用户昵称") @RequestParam("nickname") @NonNull String nickname,
                              @ApiParam("密码") @RequestParam("password") @NonNull String password,
                              @ApiParam("确认密码") @RequestParam("passwordRepeat") @NonNull String passwordRepeat) {
        // 1.基本信息赋值
        User user = new User();
        user.setUsername(username);
        user.setNickname(nickname);
        // 2.处理密码
        // 2.1 校验密码和确认密码是否相等
        if (!password.equals(passwordRepeat)) {
            log.warn(ResultCode.FAILED_TWO_PWD_NOT_SAME.toString());
            return AppResult.failed(ResultCode.FAILED_TWO_PWD_NOT_SAME);
        }
        // 2.2 加密密码
        String salt = UUIDUtil.UUID_32();
        String encryptPassword = MD5Util.md5Salt(password, salt);
        // 2.3 设置密码
        user.setPassword(encryptPassword);
        user.setSalt(salt);
        // 3. 调⽤Service
        userService.createNormalUser(user);
        // 4. 返回
        return AppResult.success();
    }

    /**
     * ⽤⼾登录
     *
     * @param request
     * @param username 用户名
     * @param password 密码
     * @return AppResult
     */
    @ApiOperation("⽤⼾登录")
    @PostMapping("/login")
    @LogAnnotation(module = "登录",operator ="执行登录操作")
//    @LogAnnotation(module = "登录",operator ="执行登录操作")
    public AppResult login (HttpServletRequest request,
                            @ApiParam(value = "⽤⼾名") @RequestParam(value = "username") @NonNull String username,
                            @ApiParam(value = "密码") @RequestParam(value = "password") @NonNull String password,
                            @ApiParam(value = "验证码") @RequestParam(value = "verificationCode") @NonNull String verificationCode){

        // 查询redis中是否有值
        String object = (String) redisTemplate.opsForValue().get(Constants.KAPTCHA_SESSION_KEY);
        if(StringUtils.isNotBlank(object)){
            // 输入的验证码是否和redis中一致
            if(object.equals(verificationCode)) {
                // 验证有效时间
                Long expire = redisTemplate.boundHashOps(Constants.KAPTCHA_SESSION_KEY).getExpire();
                System.out.println("expire->>>"+expire);
                if (expire < 0L) {
                    log.warn(ResultCode.FAILED_LOGIN_CODE_OVERTIME.toString());
                    return AppResult.failed(ResultCode.FAILED_LOGIN_CODE_OVERTIME);
                }
            }
            else {
                log.warn(ResultCode.FAILED_LOGIN_CODE.toString());
                return AppResult.failed(ResultCode.FAILED_LOGIN_CODE);
            }
        }
        else
            return AppResult.failed(ResultCode.FAILED_LOGIN);

        // 调用Service中的登录方法，返回User对象
        User user = userService.login(username, password);
        if(user==null){
            log.warn(ResultCode.FAILED_LOGIN.toString());
            return AppResult.failed(ResultCode.FAILED_LOGIN);
        }
        // 生成JWT令牌
        String token = JWTUtils.createToken(user.getId());
        System.out.println(token);

        // 获取Session - 登录成功把User对象设置到Session作用域中
        HttpSession session = request.getSession(true);
        // 把User设置到Session中
        session.setAttribute(AppConfig.USER_SESSION,user);

        // 登录成功响应
        return new AppResult<>(ResultCode.SUCCESS.getCode(),ResultCode.SUCCESS.getMessage(),token);
    }

//    @ApiOperation("⽤⼾登录")
//    @PostMapping("/login")
//    public AppResult login (HttpServletRequest request,
//                            @ApiParam(value = "⽤⼾名") @RequestParam(value = "username") @NonNull String username,
//                            @ApiParam(value = "密码") @RequestParam(value = "password") @NonNull String password){
//
//        // 调用Service中的登录方法，返回User对象
//        User user = userService.login(username, password);
//        if(user==null){
//            log.warn(ResultCode.FAILED_LOGIN.toString());
//            return AppResult.failed(ResultCode.FAILED_LOGIN);
//        }
//        // 获取Session - 登录成功把User对象设置到Session作用域中
//        HttpSession session = request.getSession(true);
//        // 把User设置到Session中
//        session.setAttribute(AppConfig.USER_SESSION,user);
//        // 登录成功响应
//        return AppResult. success ();
//    }


    /**
     * 获取用户详情
     *
     * @param id ⽤⼾ id
     * @return ⽤⼾详情
     */
    @ApiOperation("获取⽤⼾详情")
    @GetMapping("/info")
    // request:用于获取session对象 required=false：非必传参数
    public AppResult<User> getUserInfo (HttpServletRequest request,
                                        @ApiParam(value = "⽤⼾Id")
                                        @RequestParam(value = "id", required = false) Long id) {
        // 根据参数中的Id是否为空决定返回哪个⽤⼾
        // 1. id 为空，从Session中获取当前登录的用户信息，返回当前登录⽤⼾
        // 2. id 不为空，从数据库中按照ID查询指定id的⽤⼾信息
        User user = null;
        // 根据id来判断user对象的获取方式
        if (id == null) {
            // 获取Session中的⽤⼾信息
            HttpSession session = request.getSession(false); // 如果没有session，不创建
            // 判断session和用户信息是否有效
            if(session==null||session.getAttribute(AppConfig.USER_SESSION)==null)
                return AppResult.failed(ResultCode.FAILED_FORBIDDEN);
            // 获取用户信息
            user = (User) session.getAttribute(AppConfig.USER_SESSION);
        } else {
            // 根据⽤⼾Id从数据库中查询⽤⼾信息
            user = userService.selectById(id);
        }
        // 判断用户信息是否为空
        if(user==null){
            return AppResult.failed(ResultCode.FAILED_NOT_EXISTS);
        }
        return AppResult.success(user);
    }

    @ApiOperation("⽤⼾退出登录")
    @GetMapping("/logout")
    public AppResult logout (HttpServletRequest request) {
        // 获取session对象
        HttpSession session = request.getSession(false);
        // 判断session是否有效
        if (session != null) {
            log.info("退出成功");
            // 表示用户在登录情况下，直接注销session
            session.invalidate();
        }
        // 退出成功响应
        return AppResult. success ();
    }

    @Autowired
    @Qualifier("redisTemplateCustomize")
    private RedisTemplate redisTemplate;
    @GetMapping("/verification")
    public void createImageCode(HttpServletResponse response) throws IOException {
        //禁止浏览器缓存验证码信息
        response.setDateHeader("Expires", 0);
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        //设置响应格式为png图片
        response.setContentType("image/png");
        // 生成图片验证码
        BufferedImage image = new BufferedImage(300, 75, BufferedImage.TYPE_INT_RGB);
        String randomText = VerifyCodeUtils.drawRandomText(image);
        System.out.println("验证码->>>" + randomText);
        // 存入redis(设置过期时间1分钟)
        redisTemplate.opsForValue().set(Constants.KAPTCHA_SESSION_KEY, randomText, 60, TimeUnit.SECONDS);

        // 将验证码图片转换为Base64字符串
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(image, "png", baos);
        baos.flush();
        byte[] imageBytes = baos.toByteArray();
        String base64Image = Base64.getEncoder().encodeToString(imageBytes);
        baos.close();

        // 将Base64字符串作为响应发送给前端
        response.getWriter().write(base64Image);
    }

    /**
     * 修改个⼈信息
     * @param username 用户名
     * @param nickname 昵称
     * @param gender 性别
     * @param email 邮箱
     * @param phoneNum 电话号
     * @param remark 个⼈简介
     * @return AppResult
     */
    @ApiOperation("修改个⼈信息")
    @PostMapping("/modifyInfo")
    public AppResult modifyInfo (HttpServletRequest request,
                                 @ApiParam("⽤⼾名") @RequestParam(value = "username",required = false) String username,
                                 @ApiParam("昵称") @RequestParam(value = "nickname",required = false) String nickname,
                                 @ApiParam("性别") @RequestParam(value = "gender",required = false) Byte gender,
                                 @ApiParam("邮箱") @RequestParam(value = "email",required = false) String email,
                                 @ApiParam("电话号") @RequestParam(value = "phoneNum",required = false) String phoneNum,
                                 @ApiParam("个⼈简介") @RequestParam(value = "remark",required = false) String remark) {
        // 对参数做⾮空校验（全部都为空，则返回错误描述）
        if (StringUtil.isEmpty(username) && StringUtil.isEmpty(nickname)
                && StringUtil.isEmpty(email) && StringUtil.isEmpty(phoneNum)
                && StringUtil.isEmpty(remark) && gender == null) {
            return AppResult.failed("请输⼊要修改的内容");
        }
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION);
        //  封装对象
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setUsername(username);
        updateUser.setNickname(nickname);
        updateUser.setGender(gender);
        updateUser.setEmail(email);
        updateUser.setPhoneNum(phoneNum);
        updateUser.setRemark(remark);

        userService.modifyInfo(updateUser);
        // 查询最新的⽤⼾信息
        user = userService.selectById(user.getId());
        // 把最新的⽤⼾信息设置到session中
        session.setAttribute(AppConfig.USER_SESSION, user);
        return AppResult.success(user);
    }

    @ApiOperation("修改密码")
    @PostMapping("/modifyPwd")
    public AppResult modifyPassword (HttpServletRequest request,
                                     @ApiParam("原密码") @RequestParam("oldPassword") @NonNull String oldPassword,
                                     @ApiParam("新密码") @RequestParam("newPassword") @NonNull String newPassword,
                                     @ApiParam("确认密码") @RequestParam("passwordRepeat") @NonNull String passwordRepeat) {
        // 校验新密码与确认密码是否相同
        if (!newPassword.equals(passwordRepeat)) {
            return AppResult.failed(ResultCode.FAILED_TWO_PWD_NOT_SAME);
        }
        HttpSession session = request.getSession(false);
        User user = (User) session.getAttribute(AppConfig.USER_SESSION);
        userService.modifyPassword(user.getId(), newPassword, oldPassword);
        // 销毁session
        if (session != null) {
            session.invalidate();
        }
        return AppResult.success();
    }
}
